package com.ytmz.gateway.security;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.*;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;

@Slf4j
@Configuration
@Component
public class AuthorizationFilter implements GatewayFilter, Ordered {

    private RestTemplate restTemplate;
    @Value("${gateway.auth.server}")
    private String authServer;
    private SecurityProperties securityProperties;
    private AuthProperties authProperties;

    public AuthorizationFilter(SecurityProperties securityProperties, AuthProperties authProperties) {
        this.securityProperties = securityProperties;
        this.authProperties = authProperties;
        this.restTemplate = new RestTemplate();
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String authorization = getToken(exchange);
        String url = exchange.getRequest().getURI().getPath();
        String method = exchange.getRequest().getMethodValue();

        if (isSkip(url)) {
            return chain.filter(exchange);
        }
        if (isSkipPermission(url)) {
            return chain.filter(exchange);
        }
        HttpHeaders requestHeaders = new HttpHeaders();
        if (authorization != null) {
            requestHeaders.add(securityProperties.getHeader(), authorization);
        }
        HttpEntity<String> httpEntity = new HttpEntity<>(requestHeaders);
        UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(authServer).queryParam("serviceUrl", url)
                .queryParam("method", method);
        ServerHttpResponse resp = exchange.getResponse();
        try {
            ResponseEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, httpEntity,
                    String.class);
            String authTrue = response.getBody();
            if (authTrue == null || !authTrue.equals("true")) {
                resp.setStatusCode(HttpStatus.FORBIDDEN);
                return unAuth(resp, "请求未授权");
            }
        } catch (RestClientException e) {
            log.warn(e.getMessage());
            resp.setStatusCode(HttpStatus.UNAUTHORIZED);
            return unAuth(resp, "令牌认证失败");
        }

        return chain.filter(exchange);

    }

    private String getToken(ServerWebExchange exchange) {
        return AuthHelp.getTokenString(exchange, securityProperties);
    }

    private Mono<Void> unAuth(ServerHttpResponse resp, String msg) {
        resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        DataBuffer buffer = resp.bufferFactory().wrap(msg.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(buffer));
    }

    private boolean isSkip(String path) {
        return AuthProvider.getDefaultSkipUrl().stream()
                .map(url -> url.replace(AuthProvider.TARGET, AuthProvider.REPLACEMENT)).anyMatch(path::contains);
    }

    private boolean isSkipPermission(String path) {
        if (authProperties.getSkipPermissionUrl().contains("/report" + path)) {
            return true;
        }
        return authProperties.getSkipPermissionUrl().contains("/query" + path);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
